#Finds duplicate files and gives an option to remove one of them.
#Usage:
#    $>ruby execute.rb; #Then select option "duplicate". 
#
#Made on request of a friend.
require 'digest/sha1'

#TODO: Bypass symbolic links, only which point somewhere in same path.
module Com;module Googlecode;module VikrantIncubator

  $_DEBUG = false
  #$_DEBUG = true

  $_hash = {}

  def duplicate
    puts "Enter the path of the directory."
    s = gets.strip
    puts "Will leave if size of file is less than 1 MiB."
    puts "Ok?"
    gets
    recurse_for_directories s
  end

  def recurse_for_directories dir
    chunk_size = 1024 * 512 #512KiB
    leave_if_size_is_less_than = 1024 * 1024 #1 MiB
    Dir[dir + '/*'].each { |d|
      if File.directory? d
        recurse_for_directories(d)
      else
        puts "Indexing -- #{d}"
        size = File.size(d)
        next if size < leave_if_size_is_less_than
        first_chunk = IO.read(d, chunk_size)
        middle_chunk = IO.read(d, chunk_size, size / 2)
        last_chunk = IO.read(d, chunk_size, size - chunk_size) if size - chunk_size > 0
        h = Digest::SHA1.hexdigest(first_chunk + middle_chunk + last_chunk.to_s)
        #h = Digest::SHA1.hexdigest IO.read d
        if $_hash[h]
          puts "Found Duplicate"
          puts "1. #{sprintf("%.2f", File.size($_hash[h]).to_f / 1024 / 1024) } MB - #{$_hash[h]}"
          puts "2. #{sprintf("%.2f", File.size(d).to_f / 1024 / 1024) } MB - #{d}"
          puts "Delete(1/2/n)"
          s = gets.strip
          if s == 'p' #Hidden feature, will now perform complete hash check
            p = perform_complete_hash_check $_hash[h], d
            if p
              puts "They still match!"
              puts "Delete(1/2/n)"
              s = gets.strip
            else
              raise "They don't match!" #TODO: Add to $_hash
            end
          end
          if s == "1"
            File.delete($_hash[h])
            puts "Deleted #{$_hash[h]}"
            $_hash[h] = d
          elsif s == "2"
            File.delete(d)
            puts "Deleted #{d}"
          end
        else
          $_hash[h] = d
        end
      end
    }
  end
  
  def perform_complete_hash_check file1, file2
    puts "Performing complete hash check."
    puts "Indexing: #{file1}"
    h = Digest::SHA1.hexdigest IO.read file1
    puts "Indexing: #{file2}"
    h == Digest::SHA1.hexdigest(IO.read(file2))
  end

end;end;end

